複合プロトコル - Noise Protocol Framework (13)
動機
いままでは、AliceとBobがイニシエーター(Alice)によって選択された一つのNoiseプロトコルを実行することを仮定してきました。しかし、Aliceの最初のメッセージをBobが受信したあと、Bobが別のプロトコルに切り替えたいと思うケースがあります。例えば、
Bobがサポートしていない共通鍵暗号、 DH関数、ハッシュ関数、ハンドシェイクパターンなどを使用したプロトコルをAliceが選択してしまった
Aliceは、古いバージョンのBobの静的公開鍵や古いバージョンのPSKを使って"0-RTT"で暗号化されたメッセージを送信してしまった
これらのシナリオを取り扱うには、BobがAliceによって選択されたプロトコルを新しいプロトコルに切り替えるような、複合プロトコルが必要となります。そのような複合プロトコルでは、イニシエーターとレスポンダーの役割は逆になります。つまり、Bobが新しいプロトコルのイニシエーターとなり、Aliceがレスポンダーになります。
Aliceは最初のプロトコルと切り替え可能なプロトコルをBobに提示する必要があり、さらには双方が安全な移行をしなければ行けないため、複合プロ所は非常に複雑なものとなります。これらの詳細については、Noise Protocol Frameworkでは規定していませんが、複合プロトコルを構成するための"fallback"修飾子を次に定義し、それを使用して"Noise Pipe"複合プロトコルを作成する方法を例示します。
(あとで説明する)Noise PipeはXXパターンをサポートしています。しかし、一方でAliceがBobの静的公開鍵をキャッシュして0-RTT暗号化でIKハンドシェイクを試みることも可能としています。
Noise Pipeを使った動作の一例は以下のようなものとなります。
Aliceは最初にIKパターンのメッセージを送ります。
BobはAliceのメッセージを解読しようと試みます。
解読できない場合、BobはXXfallbackパターンに切り替えます。
この後はAliceがIKの最初のメッセージの代わりにXXの最初のメッセージを送信したかのように動作し、当事者たちがXXハンドシェイクを完了できるようにします。
fallback 修飾子
fallback修飾子は元のパターンの最初のメッセージをプレメッセージに変換します。例えば、XXfallbackは次の通りです。
XX: XXfallback:
-> e -> e
<- e, ee, s, es ...
-> s, se <- e, ee, s, es
-> s, se
この例で、XXfalbackの最初の"e"はプレメッセージなので、Bobはこのハンドシェイク開始前に別の手段(例えば、アリスからのIKメッセージなど)を使って、受信しておかなければいけません。このfallbackにより、ハンドシェイクはBobが開始したハンドシェイクとして解釈されます。
fallbackはAliceの最初のメッセージがプリメッセージとして解釈可能なトークンのみ("e", "s", "e, s"のいずれか)で構成されている、Alice開始形式のハンドシェイクパターンにのみ適用できます。
0-RTTとNoiseプロトコル
典型的な複合プロトコルは以下の3パターンがあります。
(1) Full protocol
Aliceが0-RTT暗号化を有効にするBobに関する情報を保持していないか、0-RTTハンドシェイクを利用したくない場合はに使用されます。
(2)0-RTT protocol
最初のメッセージでのデータの暗号化を許可するプロトコルです。
(3)Switch protocol
BobがAliceの最初の0-RTTハンドシェイクメッセージを復号化できない場合にBobによってトリガーされます。
一般的には、最初のメッセージを受信した時、Bobがフル・プロトコルと0-RTTプロトコルを区別する方法が必要です。Aliceが0-RTTを試みる時にはBobからの応答を受信した時にAliceが0-RTTかSwitchされたプロトコルかを判別する何らかの方法がなければいけません。
たとえば、それぞれのハンドシェイクメッセージにtypeのようなフィールドを先頭に付与することもできます。このようなデータはNoise Protocol Frameworkで規定していませんが、どのプロトコルが使用されているかを示すものとなります。
Noise Pipe
Noise Pipe 複合プロトコルとは、上で説明した、Full, 0-RTT, Switchのプロトコルを一つずつ使った、0-RTTをオプションとしてもつフル・ハンドシェイクを提供するためのパターンセットです。以下がNoise Pipeの例です。
XX:
-> e
<- e, ee, s, es
-> s, se
IK:
<- s
...
-> e, es, s, ss
<- e, ee, se
XXfallback:
-> e
...
<- e, ee, s, es
-> s, se
XXはフル・ハンドシェイクで、両者が事前にコミュニケーションしていない場合に使用します。
IKは0-RTTハンドシェイクで、最初のメッセージで0-RTT暗号化したデータを送信します。
XXfallbackはスイッチ・ハンドシェイクと言い、Bobが最初のIKパターンのメッセージの復号に失敗した場合に使用します。
ハンドシェイクの同一性
当事者たちは、どのタイプのハンドシェイクを行なっているかを盗聴者から隠したいと考えている場合があります。たとえば、Noise Pipeを使用していて、フル・ハンドシェイク、0-RTTハンドシェイク、スイッチ・ハンドシェイクのどれを実行しているのかを隠したいとします。
これを隠すことは簡単にできます。
(1) メッセージはどのハンドシェイクが実行されているかにかかわらず、ペイロードにランダムなバイトを一定のサイズになるように埋め込むことができます。これにより盗聴者は暗号化されたメッセージのサイズからハンドシェイクのタイプを推測できないようになります。
(2) Bobは最初に受信したメッセージをIKパターンのメッセージとして復号化しようと試みます。復号化に失敗した場合にはXXfallbackに切り替えます。
(3) Aliceは、IKパターンとして試しに復号化してみることにより、IKを使用した応答か、XXfallbackを使用した応答かを区別できます。
(4) フル・ハンドシェイクを試みるAliceは一時公開鍵を送信し、それからランダムにパディングをします。受信したレスポンスはXXfallbackを使用して処理します。ここで、XXは使用されていないことに注意してください。XXを使用すると、IKメッセージとXXメッセージを区別できないためです。
このケースでは一時公開鍵の送信については特に制約は設けていません。通常、一時公開鍵はランダムに選択されたDHの公開値ですが、盗聴者がハンドシェイクの種類を判別できない場合でも、当事者たちがNoise プロトコルを使用していると疑うには十分な構造を持ちます。一時公開鍵をランダムなバイトシーケンスと区別がつかないようにするための方法(*)も使用できるかもしれません。
(*) D. J. Bernstein, M. Hamburg, A. Krasnova, and T. Lange, “Elligator: Elliptic-curve points indistinguishable from uniform random strings.” Cryptology ePrint Archive, Report 2013/325, 2013. http://eprint.iacr.org/2013/325